/*
 * @lc app=leetcode.cn id=1115 lang=cpp
 *
 * [1115] 交替打印 FooBar
 */
#include "include.h"
// @lc code=start
class FooBar {
private:
    int n;

public:
    FooBar(int n) {
        this->n = n;
        isFoo.store(true);
    }

    void foo(function<void()> printFoo) {
        
        for (int i = 0; i < n; i++) {
            while (isFoo.load() == false){
                // wow yield
                std::this_thread::yield();
                // std::this_thread::sleep_for(std::chrono::nanoseconds(1));
                continue;
            }
        	// printFoo() outputs "foo". Do not change or remove this line.
        	printFoo();
            isFoo.store(false);
        }
    }

    void bar(function<void()> printBar) {
        
        for (int i = 0; i < n; i++) {
            while (isFoo.load() == true){
                std::this_thread::yield();
                // std::this_thread::sleep_for(std::chrono::nanoseconds(1));
                continue;
            }
        	// printBar() outputs "bar". Do not change or remove this line.
        	printBar();
            isFoo.store(true);
        }
    }

private:
    std::atomic<bool> isFoo;
};
// @lc code=end

class FooBar {
private:
    int n;
    mutex mtx;
    condition_variable cv;
    bool foo_done = false;
public:
    FooBar(int n) : n(n) {}

    void foo(function<void()> printFoo) {
        for (int i = 0; i < n; i++) {
            unique_lock<mutex> lock(mtx);
            cv.wait(lock, [&]() { return !foo_done; });
            printFoo();
            foo_done = true;
            cv.notify_one();
        }
    }

    void bar(function<void()> printBar) {
        for (int i = 0; i < n; i++) {
            unique_lock<mutex> lock(mtx);
            cv.wait(lock, [&]() { return foo_done; });
            printBar();
            foo_done = false;
            cv.notify_one();
        }
    }
};
